#include "HashTest.h"
#include "../hash/hashExtensible.h"
#include "../hash/tipoClaveInt.h"
#include "../hash/tipoClaveString.h"
#include "../hash/tipoClaveString2.h"
#include "../hash/tipoDatoInt.h"
#include "../hash/tipoDatoString.h"
#include "testTools.h"

#include <vector>	// vector

using namespace std;


// prueba usando puras cadenas 
void test2Cadenas(bool reescribirArchivo){

 //--------------------------------------------------------------------------------
 const char* dirHash  = "hash3.dat";
 const char* dirTabla = "tabla3.dat";
 const char* dirLista = "borrados3.dat";

 size_t cantRegPorBloque = 3;

 hashExtensible<TipoDatoString,tipoClaveString> hash(dirHash,dirTabla,dirLista,reescribirArchivo,cantRegPorBloque);

 //--------------------------------------------------------------------------------

 TipoDatoString dato("mmmmm, aca");
 tipoClaveString clave("1->123");
 hash.agregar(&clave,&dato);
 
 dato.setDato("hay");
 clave.setClave("2->629");
 hash.agregar(&clave,&dato);

 dato.setDato("demasiados");
 clave.setClave("3->915");
 hash.agregar(&clave,&dato);

 dato.setDato("datos");
 clave.setClave("4->411");
 hash.agregar(&clave,&dato);

 dato.setDato("guardados");
 clave.setClave("5->200");
 hash.agregar(&clave,&dato);
 
 dato.setDato("en");
 clave.setClave("6->863");
 hash.agregar(&clave,&dato);

 clave.setClave("2->629");
 hash.borrar(&clave);

 dato.setDato("este");
 clave.setClave("7->408");
 hash.agregar(&clave,&dato);

 dato.setDato("maldito");
 clave.setClave("8->34");
 hash.agregar(&clave,&dato);

 dato.setDato("hash");
 clave.setClave("9->510");
 hash.agregar(&clave,&dato);

 clave.setClave("6->863");
 hash.borrar(&clave);

 dato.setDato(".....");		// este reutiliza el bloque 0 (borrado)
 clave.setClave("10->775");
 hash.agregar(&clave,&dato);

 dato.setDato("estoy repetido!!!"); // este si tendria q insertarse --> clave repetida, pero nuevo dato
 clave.setClave("10->775");
 hash.agregar(&clave,&dato);

 dato.setDato("estoy repetido!!!"); // este no tendria q insertarse --> dato y clave repetidos
 clave.setClave("10->775");
 hash.agregar(&clave,&dato);

 hash.imprimir();

 //--------------------------------------------------------------------------------

 tipoClaveString claveBusqueda("3->914"); // lo que importa al compararlos es la cadena
 vector<TipoDatoString> datoBusqueda;

 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
 	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 claveBusqueda.setClave("3->915");
 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
 	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 //--------------------------------------------------------------------------------
}


// prueba usando cadenas como datos y enteros como claves
void testCadenas(bool reescribirArchivo){

 //--------------------------------------------------------------------------------
 const char* dirHash  = "hash2.dat";
 const char* dirTabla = "tabla2.dat";
 const char* dirLista = "borrados2.dat";
 size_t cantRegPorBloque = 3;

 hashExtensible<TipoDatoString,tipoClaveString2> hash(dirHash,dirTabla,dirLista,reescribirArchivo,cantRegPorBloque);

 //--------------------------------------------------------------------------------

 TipoDatoString dato("mmmmm, aca");
 tipoClaveString2 clave(123,"1->123");
 hash.agregar(&clave,&dato);
 
 dato.setDato("hay");
 clave.setClave(629,"2->629");
 hash.agregar(&clave,&dato);

 dato.setDato("demasiados");
 clave.setClave(915,"3->915");
 hash.agregar(&clave,&dato);
 
 dato.setDato("datos");
 clave.setClave(411,"4->411");
 hash.agregar(&clave,&dato);

 dato.setDato("guardados");
 clave.setClave(200,"5->200");
 hash.agregar(&clave,&dato);

 dato.setDato("en");
 clave.setClave(863,"6->863");
 hash.agregar(&clave,&dato);

 clave.setClave(629,"2->629");
 hash.borrar(&clave);

 dato.setDato("este");
 clave.setClave(408,"7->408");
 hash.agregar(&clave,&dato);

 dato.setDato("maldito");
 clave.setClave(34,"8->34");
 hash.agregar(&clave,&dato);

 dato.setDato("hash");
 clave.setClave(510,"9->510");
 hash.agregar(&clave,&dato);

 clave.setClave(863,"6->863");
 hash.borrar(&clave);

 dato.setDato(".....");		// este reutiliza el bloque 0 (borrado)
 clave.setClave(775,"10->775");
 hash.agregar(&clave,&dato);

 dato.setDato("estoy repetido!!!"); // este si tendria q insertarse --> clave repetida, pero nuevo dato
 clave.setClave(775,"10->775");
 hash.agregar(&clave,&dato);

 dato.setDato("estoy repetido!!!"); // este no tendria q insertarse --> dato y clave repetidos
 clave.setClave(775,"10->775");
 hash.agregar(&clave,&dato);

 hash.imprimir();

 //--------------------------------------------------------------------------------

 tipoClaveString2 claveBusqueda(915,"3->914"); // lo que importa al compararlos es la cadena
 vector<TipoDatoString> datoBusqueda;

 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
 	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 claveBusqueda.setClave(915,"3->915");
 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
 	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 //--------------------------------------------------------------------------------
}

// prueba usando datos y claves enteras
void testEnteros(bool reescribirArchivo){

 //--------------------------------------------------------------------------------

 const char* dirHash  = "hash.dat";
 const char* dirTabla = "tabla.dat";
 const char* dirLista = "borrados.dat";
 size_t cantRegPorBloque = 3;
 hashExtensible<TipoDatoInt,tipoClaveInt> hash(dirHash,dirTabla,dirLista,reescribirArchivo,cantRegPorBloque);

 //--------------------------------------------------------------------------------

 cout << "\nCreo hash vacío: \n";
 hash.imprimir();

 TipoDatoInt dato(10);
 tipoClaveInt clave(123);
 hash.agregar(&clave,&dato);
 
 dato.setDato(20);
 clave.setClave(629); 
 hash.agregar(&clave,&dato);

 dato.setDato(30);
 clave.setClave(915); 
 hash.agregar(&clave,&dato);
 
 cout << "\nAgrego los 3 primeros datos: \n";
 hash.imprimir();

 dato.setDato(40);
 clave.setClave(411); 
 hash.agregar(&clave,&dato);
 
 cout << "\nAgrego el cuarto y se redimensiona 2 veces: (caso 1) \n";
 hash.imprimir();

 dato.setDato(50);
 clave.setClave(200); 
 hash.agregar(&clave,&dato);

 cout << "\nAgrego el el quinto: \n";
 hash.imprimir();

 dato.setDato(60);
 clave.setClave(863); 
 hash.agregar(&clave,&dato);

 cout << "\nAgrego el el sexto y se vuelve a redimensionar: (caso1) \n";
 hash.imprimir();

 clave.setClave(629); 
 hash.borrar(&clave);

 cout << "\nborro un elemento, bloque 2 queda vacio, pero no lo livero: \n";
 hash.imprimir();

 dato.setDato(70);
 clave.setClave(408); 
 hash.agregar(&clave,&dato);

 dato.setDato(80);
 clave.setClave(34); 
 hash.agregar(&clave,&dato);

 cout << "\nAgrego dos mas: \n";
 hash.imprimir();

 dato.setDato(90);
 clave.setClave(510); 
 hash.agregar(&clave,&dato);

 cout << "\nAgrego el noveno y se redimensiona: (caso2)\n";
 hash.imprimir();

 clave.setClave(863); 
 hash.borrar(&clave);

 cout << "\nborro y esta vez si livero el bloque (bloque 0) y se achica la tabla de dispersion: \n";
 hash.imprimir();

 dato.setDato(100);     // este reutiliza el bloque 0 (borrado) 
 clave.setClave(775); 
 hash.agregar(&clave,&dato);

 dato.setDato(110);     // este si tendria q insertarse --> clave repetida, pero nuevo dato
 clave.setClave(775); 
 hash.agregar(&clave,&dato);

 cout << "\nagrego dos claves repetidas, ambas se insertan y se reutiliza el bloque 0 al redimensionar:\n";
 hash.imprimir();

 dato.setDato(100);     // este no tendria q insertarse --> dato y clave repetidos
 clave.setClave(775); 
 hash.agregar(&clave,&dato);

 cout << "\nagrego clave y dato repetidas no se inserta:\n";
 hash.imprimir();

 //hash.imprimir();

 //--------------------------------------------------------------------------------

 tipoClaveInt claveBusqueda(914);
 vector<TipoDatoInt> datoBusqueda;

 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
 	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 claveBusqueda.setClave(915);
 hash.buscar(&claveBusqueda,&datoBusqueda);

 if (datoBusqueda.empty())
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: inexistente \n\n";  
 else 
  	cout << "CLAVE: " << claveBusqueda << "\nDATO: " << datoBusqueda[0] << "\n\n";

 //--------------------------------------------------------------------------------
}

void testDatoString(){
 TipoDatoString dato("hola a todo el mundo!!");
	
 cout << "\n\nTest datoString:";

 cout << "\n\nCreo nuevo dato:";
 imprimirSelectivo("\nobtener el tamaño: \t", (dato.obtenerTamanio() == 29) );
 imprimirSelectivo("\nobtener el largo: \t", (dato.getLargo() == 22) );
 imprimirSelectivo("\nobtener el dato: \t", sonIguales(dato.getDato(),"hola a todo el mundo!!") );

 char buffer[40] = "ja ja ja jo jo jo ji ji ji je je je";
 dato.serializar(buffer);

 cout << "\n\nSerializo el dato e inspecciono el buffer:";
 imprimirSelectivo("\ninspecciono el largo: \t", ((size_t)(*buffer) == 22));
 imprimirSelectivo("\ninspecciono el dato: \t", sonIguales((char*)(buffer+sizeof(size_t)),"hola a todo el mundo!!"));

 dato.setDato((char*)"chau mundo!!!");
 imprimirSelectivo("\ncambio el dato:  \t",sonIguales(dato.getDato(),"chau mundo!!!") );

 dato.desSerializar(buffer);

 cout << "\n\nrecupero el dato del buffer:\t\t";
 imprimirSelectivo("\nobtener el tamaño: \t", (dato.obtenerTamanio() == 29) );
 imprimirSelectivo("\nobtener el largo: \t", (dato.getLargo() == 22) );
 imprimirSelectivo("\nobtener el dato: \t", sonIguales(dato.getDato(),"hola a todo el mundo!!") );

 cout << "\n";
}
